package com.xbongbong.paas.business.rule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.RuleOperationEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.FilterConditionsPoJo;
import com.xbongbong.paas.field.LinkInfoPojo;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.pojo.BusinessRulesPoJo;
import com.xbongbong.paas.pojo.RulePoJo;
import com.xbongbong.paas.pojo.vo.LinkResultDataDTO;
import com.xbongbong.paas.pojo.vo.LinkResultDataVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.HookMethodUtil;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.condition.ConditionFieldHandler;
import com.xbongbong.parent.condition.ConditionFieldHandlerFactory;
import com.xbongbong.parent.condition.ProConditionHelp;
import com.xbongbong.parent.util.LinkDataUtil;
import com.xbongbong.pro.businessrule.pojo.BusinessRuleInfoPojo;
import com.xbongbong.pro.businessrule.pojo.dto.OperatorBatchDTO;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogSaveDTO;
import com.xbongbong.pro.enums.businessrule.enums.RuleValueTypeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.permission.pojo.dto.VerifyAddPermissionDTO;
import com.xbongbong.pro.permission.pojo.dto.VerifyDeletePermissionDTO;
import com.xbongbong.pro.permission.pojo.dto.VerifyUpdatePermissionDTO;
import com.xbongbong.saas.domain.entity.WorkOrderExplainEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.sys.help.ProPermissionHelp;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author 吴峰
 * @version v1.0
 * @date 2019/9/19 16:12
 * @since v1.0
 */
@Component
public abstract class AbstractRuleHelp {

    protected static final Integer ACTIVE_BUSINESS_RULE_TYPE = 1;

    protected static final Integer INACTIVE_BUSINESS_RULE_TYPE = 2;

    @Resource
    private ProConditionHelp proConditionHelp;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BusinessRuleLogService businessRuleLogService;
    @Resource
    private BusinessRuleConditionHelp businessRuleConditionHelp;
    @Resource
    private ConditionFieldHandlerFactory conditionFieldHandlerFactory;

    /**
     * 发送消息
     * @param operatorBatchDTO
     * @throws XbbException
     */
    public abstract void sendMessage(OperatorBatchDTO operatorBatchDTO) throws XbbException;


    /**
     * 校验权限
     * @param rulePoJo
     */
    protected void validatePermission(RulePoJo rulePoJo, UserVO userVO) throws XbbException {
        Integer operationType = rulePoJo.getOperationType();
        RuleTargetPojo ruleTargetPojo = rulePoJo.getTarget();
        if (Objects.equals(RuleOperationEnum.ONLY_UPDATE.getType(), operationType)) {
            // 编辑权限校验
            VerifyUpdatePermissionDTO verifyUpdatePermissionDTO = new VerifyUpdatePermissionDTO();
            verifyUpdatePermissionDTO.setLoginUser(userVO);
            verifyUpdatePermissionDTO.setLoginUser(userVO);
            verifyUpdatePermissionDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
            verifyUpdatePermissionDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
            verifyUpdatePermissionDTO.setMenuId(ruleTargetPojo.getMenuId());
            ProPermissionHelp.verifyEditPermission(verifyUpdatePermissionDTO);
        } else if (Objects.equals(RuleOperationEnum.ONLY_INSERT.getType(), operationType)) {
            // 新建
            VerifyAddPermissionDTO verifyAddPermissionDTO = new VerifyAddPermissionDTO();
            verifyAddPermissionDTO.setLoginUser(userVO);
            verifyAddPermissionDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
            verifyAddPermissionDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
            verifyAddPermissionDTO.setMenuId(ruleTargetPojo.getMenuId());
            ProPermissionHelp.verifyAddPermission(verifyAddPermissionDTO);
        } else if (Objects.equals(RuleOperationEnum.UPDATE_AND_INSERT.getType(), operationType)) {
            // 编辑权限校验
            VerifyUpdatePermissionDTO verifyUpdatePermissionDTO = new VerifyUpdatePermissionDTO();
            verifyUpdatePermissionDTO.setLoginUser(userVO);
            verifyUpdatePermissionDTO.setLoginUser(userVO);
            verifyUpdatePermissionDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
            verifyUpdatePermissionDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
            verifyUpdatePermissionDTO.setMenuId(ruleTargetPojo.getMenuId());
            ProPermissionHelp.verifyEditPermission(verifyUpdatePermissionDTO);
            // 新建
            VerifyAddPermissionDTO verifyAddPermissionDTO = new VerifyAddPermissionDTO();
            verifyAddPermissionDTO.setLoginUser(userVO);
            verifyAddPermissionDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
            verifyAddPermissionDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
            verifyAddPermissionDTO.setMenuId(ruleTargetPojo.getMenuId());
            ProPermissionHelp.verifyAddPermission(verifyAddPermissionDTO);
        } else if (Objects.equals(RuleOperationEnum.ONLY_DELETE.getType(), operationType)) {
            VerifyDeletePermissionDTO verifyDeletePermissionDTO = new VerifyDeletePermissionDTO();
            verifyDeletePermissionDTO.setLoginUser(userVO);
            verifyDeletePermissionDTO.setSaasMark(ruleTargetPojo.getLinkSaasMark());
            verifyDeletePermissionDTO.setBusinessType(ruleTargetPojo.getLinkBusinessType());
            verifyDeletePermissionDTO.setMenuId(ruleTargetPojo.getMenuId());
            ProPermissionHelp.verifyDeletePermission(verifyDeletePermissionDTO);
        }
    }


    /**
     * 记录日志
     * @param businessRuleLogSaveDTO
     * @param businessRuleId 业务规则id
     * @param operationType 业务规则执行的操作
     *  @see com.xbongbong.paas.enums.BusinessRuleExecuteEnum
     * @param message
     * @see com.xbongbong.paas.enums.BusinessRuleExecuteEnum
     * @param reason
     * @param target 目标表单实体
     * @param executeResult 业务规则最终执行的操作
     * @param executeNum 更新的数量
     * @param consumer 1：执行成功 0： 执行失败
     * @throws XbbException
     */
    protected void setLogger(BusinessRuleLogSaveDTO businessRuleLogSaveDTO, Long businessRuleId, Integer operationType,
                             String message, Integer reason, RuleTargetPojo target, Integer executeResult, Integer executeNum, Integer consumer) throws XbbException {
        businessRuleLogSaveDTO.setBusinessRuleInfoId(businessRuleId);
        businessRuleLogSaveDTO.setOperationType(operationType);
        businessRuleLogSaveDTO.setMessage(message);
        businessRuleLogSaveDTO.setReason(reason);
        businessRuleLogSaveDTO.setRedisKey("");
        businessRuleLogSaveDTO.setTarget(target);
        businessRuleLogService.log(businessRuleLogSaveDTO, executeResult, executeNum, consumer);
    }


    /**
     * 获取检索条件
     * @param filterConditions 过滤条件
     * @param paasFormDataEntity 数据实体
     * @param businessRuleInfoPojo
     * @return
     */
    public List<ConditionsEntityExt> getConditionList(List<FilterConditionsPoJo> filterConditions, PaasFormDataEntity paasFormDataEntity,
                                                      BusinessRuleInfoPojo businessRuleInfoPojo) throws XbbException {
        List<ConditionsEntityExt> conditionList = new ArrayList<>();
        if (Objects.isNull(paasFormDataEntity)) {
            return new ArrayList<>();
        }
        // 遍历过滤条件，组装条件查询
        FieldAttrEntity dataIdFieldAttrEntity = proConditionHelp.getDataIdFieldAttr();
        Map<String, FieldAttrEntity> targetExplainMap = businessRuleInfoPojo.getTargetExplainMap();
        targetExplainMap.put(FieldTypeEnum.DATAID.getAlias(), dataIdFieldAttrEntity);
        Map<String, FieldAttrEntity> thisExplainMap = businessRuleInfoPojo.getThisExplainMap();
        thisExplainMap.put(FieldTypeEnum.DATAID.getAlias(), dataIdFieldAttrEntity);
        for (FilterConditionsPoJo filterCondition : filterConditions) {
            String attr = filterCondition.getAttr();
            if (StringUtil.isEmpty(attr)) {
                continue;
            }
            Object object;
            Integer targetFieldType = filterCondition.getFieldType();
            List<String> targetAttrArray = ExplainUtil.getAttrByPoint(attr);
            String targetSubAttr = "";
            if (targetAttrArray.size() == 2) {
                attr = targetAttrArray.get(0);
                targetSubAttr = targetAttrArray.get(1);
            }
            // 获取动态值
            if(Objects.equals(filterCondition.getValueType(), RuleValueTypeEnum.DYNAMIC_VALUE.getType())){
                String thisAttr = filterCondition.getValueAttr();
                if (Objects.isNull(targetFieldType) || StringUtil.isEmpty(thisAttr)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.THIS_EXPLAIN_NOT_EXIST);
                }
                List<String> thisAttrArray = ExplainUtil.getAttrByPoint(thisAttr);
                if (thisAttrArray.size() == 2) {
                    thisAttr = thisAttrArray.get(0);
                }
                FieldAttrEntity fieldAttrEntity = thisExplainMap.get(thisAttr);

                FieldAttrEntity targetField = targetExplainMap.get(attr);
                if (Objects.isNull(fieldAttrEntity) || Objects.isNull(targetField)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.THIS_EXPLAIN_NOT_EXIST);
                }
                if (ExplainUtil.isSubForm(targetField.getFieldType())) {
                    // 目标表单为子表单的字段时
                    List<? extends FieldAttrEntity> jsonArray = targetField.getSubForm().getItems();
                    Map<String, FieldAttrEntity> targetSubExplainMap = ExplainUtil.getExplainMapByList(jsonArray);
                    targetField = targetSubExplainMap.get(targetSubAttr);
                    targetFieldType = targetField.getFieldType();
                    object = businessRuleConditionHelp.getValueByData(fieldAttrEntity, targetField, paasFormDataEntity, businessRuleInfoPojo, thisExplainMap, filterCondition, thisAttrArray);
                } else {
                    object = businessRuleConditionHelp.getValueByData(fieldAttrEntity, targetField, paasFormDataEntity, businessRuleInfoPojo, thisExplainMap, filterCondition, thisAttrArray);
                }
            } else {
                // 固定值

                FieldAttrEntity targetField = targetExplainMap.get(attr);
                if (Objects.isNull(targetField)) {
                    return new ArrayList<>();
                }
                if (ExplainUtil.isSubForm(targetField.getFieldType())) {
                    // 目标表单为子表单的字段时
                    List<? extends FieldAttrEntity> jsonArray = targetField.getSubForm().getItems();
                    Map<String, FieldAttrEntity> targetSubExplainMap = ExplainUtil.getExplainMapByList(jsonArray);
                    targetField = targetSubExplainMap.get(targetSubAttr);
                    targetFieldType = targetField.getFieldType();
                    ConditionFieldHandler conditionFieldHandler = conditionFieldHandlerFactory.getHandlerFixedValueByFieldType(targetFieldType);
                    object = conditionFieldHandler.handlerFixedValue(targetField, businessRuleInfoPojo, filterCondition);
                } else {
                    ConditionFieldHandler conditionFieldHandler = conditionFieldHandlerFactory.getHandlerFixedValueByFieldType(targetFieldType);
                    object = conditionFieldHandler.handlerFixedValue(targetField, businessRuleInfoPojo, filterCondition);
                }
            }
            ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt(attr, targetSubAttr, targetFieldType, filterCondition.getSymbol());
            if (proConditionHelp.isEmpty(object, targetFieldType)) {
                String symbol = ConditionEnum.EMPTY.getSymbol();
                if (Objects.equals(conditionsEntityExt.getSymbol(), ConditionEnum.NOEQUAL.getSymbol())) {
                    symbol = ConditionEnum.NOEMPTY.getSymbol();
                }
                conditionsEntityExt.setSymbol(symbol);
                conditionList.add(conditionsEntityExt);
                continue;
            }
            if (Objects.equals(FieldTypeEnum.NUM.getType(), targetFieldType) && !RegexUtil.isNumber(object.toString()) && !(object instanceof List)) {
                // 当过滤条件为数字字段时，对比时仅需实际值相等即可，不需要匹配小数位数。
                // 必须是数字类型， 否则不执行正则
                return new ArrayList<>();
            }

            if(object instanceof List){
                List<Object> list = JSON.parseArray(JSON.toJSONString(object), Object.class);
                conditionsEntityExt.setValue(list);
            } else if (Objects.equals(FieldTypeEnum.DATAID.getAlias(), filterCondition.getValueAttr())
                    && Objects.nonNull(paasFormDataEntity.getId())) {
                conditionsEntityExt.setValue(Arrays.asList(paasFormDataEntity.getId()));
            } else {
                List<Object> list = new ArrayList<>();
                list.add(object);
                conditionsEntityExt.setValue(list);
            }

            conditionList.add(conditionsEntityExt);
        }

        return conditionList;
    }



    public void getFormId(List<BusinessRulesPoJo> businessRules, Set<Long> workOrderFormIdList, Set<Long> formIdList) {
        businessRules.forEach(businessRulesPoJo->{
            if (Objects.nonNull(businessRulesPoJo.getActiveRule())) {
                RuleTargetPojo rulePoJo = businessRulesPoJo.getActiveRule().getRule().getTarget();
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), rulePoJo.getLinkBusinessType())) {
                    workOrderFormIdList.add(rulePoJo.getFormId());
                } else {
                    formIdList.add(rulePoJo.getFormId());
                }
            }
            if (Objects.nonNull(businessRulesPoJo.getInactiveRule()) && Objects.nonNull(businessRulesPoJo.getInactiveRule().getRule())) {
                RuleTargetPojo rulePoJo = businessRulesPoJo.getInactiveRule().getRule().getTarget();
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), rulePoJo.getLinkBusinessType())) {
                    workOrderFormIdList.add(rulePoJo.getFormId());
                } else {
                    formIdList.add(rulePoJo.getFormId());
                }
            }
        });
    }

    /**
     * 根据目标表单的属性获取其字段容器
     * @param businessRuleInfoPojo 业务规则需要的一些属性容器（字段表，目标表单）
     * @return 目标表单的字段容器
     */
    public Map<String, FieldAttrEntity> getTargetExplainMap(BusinessRuleInfoPojo businessRuleInfoPojo) throws XbbException {
        Map<Long, PaasFormExplainEntity> formExplainMap = businessRuleInfoPojo.getFormExplainMap();
        Map<Long, WorkOrderExplainEntity> workOrderExplainMap = businessRuleInfoPojo.getWorkOrderExplainMap();
        RuleTargetPojo target = businessRuleInfoPojo.getRuleTargetPojo();
        Long formId = target.getFormId();
        Map<String, FieldAttrEntity> targetExplainMap;
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), target.getLinkBusinessType())) {
            WorkOrderExplainEntity workOrderExplainEntity = workOrderExplainMap.get(formId);
            if (Objects.isNull(workOrderExplainEntity)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.THIS_EXPLAIN_NOT_EXIST);
            }
            targetExplainMap = ExplainUtil.getExplainMap(workOrderExplainEntity.getExplains(), null);
        } else {
            PaasFormExplainEntity paasFormExplainEntity = formExplainMap.get(formId);
            if (Objects.isNull(paasFormExplainEntity)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.THIS_EXPLAIN_NOT_EXIST);
            }
            targetExplainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
        }
        ProFormHelp.setDataIdAttr(targetExplainMap);
        return targetExplainMap;
    }

    /**
     * 获取关联数据字段的数据
     */

    protected void getFormDataMap(PaasFormDataEntity paasFormDataEntity, List<FieldAttrEntity> explainList, BusinessRuleInfoPojo businessRuleInfoPojo) throws XbbException{
        Map<String, PaasFormDataEntityExt> formDataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        businessRuleInfoPojo.setFormDataMap(formDataMap);
        Map<String, LinkInfoPojo> linkInfoPojoMap = LinkDataUtil.getLinkInfoMap(explainList);
        if (linkInfoPojoMap.isEmpty()) {
            return;
        }
        JSONObject data = paasFormDataEntity.getData();
        JSONObject subFormData = paasFormDataEntity.getSubFormData() == null ? new JSONObject(): paasFormDataEntity.getSubFormData();
        Iterator<String> iterator = linkInfoPojoMap.keySet().iterator();
        Set<Object> dataSet = new HashSet<>();
        while (iterator.hasNext()) {
            String key = iterator.next();
            List<String> attrList = ExplainUtil.getAttrByPoint(key);
            if (attrList.size() == 2) {
                key = attrList.get(0);
                JSONArray subDataList = subFormData.getJSONArray(key);
                if (Objects.nonNull(subDataList)) {
                    String subKey = attrList.get(1);
                    for (int i = 0; i < subDataList.size(); i++) {
                        JSONObject subData = subDataList.getJSONObject(i);
                        if (HookMethodUtil.isLegalData(subData, subKey)){
                            dataSet.add(subData.get(subKey));
                        }
                    }
                }
            } else if (HookMethodUtil.isLegalData(data, key)){
                dataSet.add(data.get(key));
            }
        }
        if (dataSet.isEmpty()) {
            return;
        }
        LinkResultDataDTO linkResultDataDTO = new LinkResultDataDTO();
        linkResultDataDTO.setSearchUserTeam(false);
        linkResultDataDTO.setCorpid(businessRuleInfoPojo.getCorpid());
        LinkResultDataVO linkResultDataVO = new LinkResultDataVO();
        linkResultDataVO.setExplainList(explainList);
        linkResultDataVO.setLinkDataSet(dataSet);
        formDataMap = proFormHelp.ruleGetLinkDataOfBusinessType(linkResultDataDTO, linkResultDataVO);
        businessRuleInfoPojo.setFormDataMap(formDataMap);
    }


}
